package com.shoute.ai.controller;


import com.shoute.ai.repository.ChatHistoryRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.ai.transformer.splitter.TextSplitter;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.util.Arrays;
import java.util.List;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;

@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/ai/doc")
public class DocumentController {

    private final VectorStore redisVectorStore;

    private final ChatClient docChatClient;

    private final ChatHistoryRepository chatHistoryRepository;

    private final RedisTemplate redisTemplate;

    @RequestMapping(value = "/all/chat", produces = "text/html;charset=utf-8")
    public Flux<String> allChat(String prompt, String chatId) {
        // 2.保存会话id
        chatHistoryRepository.save("doc", chatId);
        // 3.请求模型
        return docChatClient.prompt()
                .user(prompt)
                .advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId))
                .stream()
                .content();
    }


    @RequestMapping(value = "/single/chat", produces = "text/html;charset=utf-8")
    public Flux<String> singleChat(String prompt, String chatId) {
        //找对应文档的url
//        String url = "https://www.gjtool.cn/pdfh5/git.pdf";
//        String fileFingerprint = DigestUtils.md5Hex(url.getBytes());
//        List<Document> documents = redisVectorStore.similaritySearch(
//                SearchRequest.builder().query("")
//                        .filterExpression("file_fingerprint=='" + fileFingerprint+"'" )
//                        //源码  tok 默认值为4，超过4需要设置tok
//                        .topK(1000).build());
//
//        if(CollectionUtils.isEmpty(documents)){
//            syncFile(url);
//        }
//        //  方式一：这种方式，减少数据库开销  如果使用该方式   上面查询的topk尽量设置大些，只有一个文档内容，应该不会内存溢出，小的话可能获取不到所有内容。           如果使用下面直接查询数据库方式  topk设置1  减少数据库开销
//        String context = documents.stream()
//                .map(Document::getText)
//                .collect(Collectors.joining("\n"));
//        String augmentedPrompt = "Context:\n" + context + "\n\nQuestion: " + prompt;
        // 2.保存会话id
        chatHistoryRepository.save("doc", chatId);
        // 3.请求模型
        return docChatClient.prompt()
                .user(prompt) // 使用方式一  ：augmentedPrompt    方式二：prompt
                .advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId))
                //方式二：该方式查数据库两次
//                .advisors(new QuestionAnswerAdvisor(
//                        redisVectorStore,
//                        SearchRequest.builder().query("")
//                                .filterExpression("file_fingerprint=='" + fileFingerprint+"'" )
//                                .topK(100).build()
//                ))
                .stream()
                .content();
    }



    @PostMapping("/sync")
    public String docSyncVectorStore()  {
        try{
            List<String> urls = Arrays.asList("C:\\Users\\admin\\Desktop\\project\\波康健\\Final-联康集团-2025数字化营销部考核政策(2).docx",  "C:\\Users\\admin\\Desktop\\project\\波康健\\联康集团-广阔市场事业部2025年度绩效考核管理政策.pdf"
            ,"C:\\Users\\admin\\Desktop\\project\\波康健\\联康集团-核心市场事业部2025年度绩效考核管理政策.pdf","C:\\Users\\admin\\Desktop\\project\\波康健\\联康集团-医美产品（肌颜态）市场推广激励机制-20250226（廖兵、SFE确认版本）.docx");

//            List<String> urls = Arrays.asList("https://www.gjtool.cn/pdfh5/git.pdf");
            log.info("===============插入开始=============");
            for (int j= 0 ;j < urls.size(); j++) {
                String url = urls.get(j);
                log.info("第 "+(j+1)+" 个文档");
                syncFile(url);
            }
            log.info("===============插入结束=============");
        }catch (Exception e){
            e.printStackTrace();
        }

        return "success";
    }

    private void syncFile(String url){
        String fileFingerprint = DigestUtils.md5Hex(url.getBytes());
        log.info("文件指纹："+fileFingerprint);
        if(!redisTemplate.hasKey("processed:" + fileFingerprint)){
            TikaDocumentReader reader;
            if(!url.contains("http")){
                //本地文档使用这种方式
                Resource resource = new FileSystemResource(url);
                reader = new TikaDocumentReader(resource);
            }else {
                //url使用这种方式     http方式
                reader = new TikaDocumentReader(url);
            }
            // 读取PDF文档，拆分为Document
            List<Document> documents = reader.get();
            // 使用 TextSplitter 分块
            TextSplitter splitter = new TokenTextSplitter();
            List<Document> apply = splitter.apply(documents);
            apply.forEach(document -> {
                document.getMetadata().put("source_url", url);
                document.getMetadata().put("file_fingerprint", fileFingerprint);
            });
            // 写入向量库
            int batchSize = 10;
            for (int i = 0; i < apply.size(); i += batchSize) {
                List<Document> subList = apply.subList(i, Math.min(i + batchSize, apply.size()));
                redisVectorStore.add(subList);
            }
            redisTemplate.opsForValue().set("processed:" + fileFingerprint, "true");
        }
    }

}
